package com.cloudpan.service.impl;


import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.lang.UUID;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudpan.common.CommonConstants;
import com.cloudpan.common.RedisCache;
import com.cloudpan.common.ResultCodeMsg;
import com.cloudpan.entity.bo.*;
import com.cloudpan.entity.pojo.SysFileInfo;
import com.cloudpan.entity.pojo.SysUserInfo;
import com.cloudpan.entity.vo.SysUserInfoVo;
import com.cloudpan.common.exception.GlobalExceptionHandler;
import com.cloudpan.mapper.SysUserInfoMapper;
import com.cloudpan.service.SysFileInfoService;
import com.cloudpan.service.SysUserInfoService;
import com.cloudpan.utils.SMSUtils;
import com.cloudpan.utils.ValidateCodeUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author sc
 * @since 2023-10-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class SysUserInfoServiceImpl extends ServiceImpl<SysUserInfoMapper, SysUserInfo> implements SysUserInfoService {

    private final SysUserInfoMapper sysUserInfoMapper;

    private final RedisCache redisCache;

    private final AmazonS3 amazonS3;

    @Value("${cloudpan.signNameKey}")
    private static String signNameKey;

    @Value("${cloudpan.templateCode}")
    private static String templateCode;

    @Override
    public Boolean register(SysUserInfoBo condition, HttpSession session) {
        SysUserInfo sysUserInfo = new SysUserInfo();
        if (!condition.getPassword().equals(condition.getPasswordTwo())) {
            throw new GlobalExceptionHandler("两次密码输入不一致,请重新输入");
        }
        //验证码
        String code = (String) session.getAttribute(CommonConstants.CHECK_CODE_KEY);
        if (!"246810".equals(condition.getCode())){
            throw new GlobalExceptionHandler("验证码错误");
        }
        condition.setPassword(BCrypt.hashpw(condition.getPasswordTwo(), BCrypt.gensalt()));
        BeanUtils.copyProperties(condition, sysUserInfo);
        //设置用户初始化大小10g 和  已使用空间0
        sysUserInfo.setUseSpace(0L);
        sysUserInfo.setTotalSpace(CommonConstants.USERINITUSESPACE * CommonConstants.GB);
        sysUserInfoMapper.insert(sysUserInfo);
        //用户注册 给用户创建一个桶存储
        try {
            String userId = sysUserInfo.getUserId();
            amazonS3.createBucket(userId);
            //SetBucketPolicyRequest setBucketPolicyRequest = new SetBucketPolicyRequest(userId,"public");
            //amazonS3.setBucketPolicy(setBucketPolicyRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalExceptionHandler("创建用户失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 查询用户输入的表单信息是否存在数据库
     * @param condition
     * @return
     */
    @Override
    public Boolean selectByCodition(SysUserInfoBo condition) {
        SysUserInfo check = this.sysUserInfoMapper.selectByCodition(condition);
        if (!ObjectUtils.isEmpty(check)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 手机号或学号登陆mapper
     * @param condition
     * @return
     */
    @Override
    public SysUserInfoVo login(SysUserPasswordLoginBo condition, HttpSession session) {
        Boolean phone = isPhone(condition.getAccountNumber());
        //如果是手机号登陆则false  学号true 手机号false
        if (phone){
            condition.setFlag(Boolean.FALSE);
        }
        SysUserInfo info = sysUserInfoMapper.login(condition);
        //账号错误
        if (ObjectUtils.isEmpty(info)){
            throw  new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_NUMBER_ERROR);
        }
        SysUserInfoVo vo = new SysUserInfoVo();
        BeanUtils.copyProperties(info,vo);
        //密码错误
        boolean checkpw = BCrypt.checkpw(condition.getPassword(), info.getPassword());
        if (!checkpw){
            throw  new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_PASSWORD_ERROR);
        }
        //验证码
        String code = (String) session.getAttribute(CommonConstants.CHECK_CODE_KEY);
        //验证码错误
        if (!condition.getCode().equalsIgnoreCase(code)){
            throw  new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_CODE_ERROR);
        }
        //账号已被禁用
        if (vo.getStatus().equals(ResultCodeMsg.ACCOUNT_DISABLE.getCode() + "")){
            throw  new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_DISABLE);
        }
        //这样写主要是重置最后登陆时间
        sysUserInfoMapper.deleteById(vo.getUserId());
        sysUserInfoMapper.insert(info);
        return vo;
    }

    /**
     * 发送手机验证码 只能发送18690768261手机号
     * @param phone
     * @return
     */
    @Override
    public Boolean smspush(String phone) {
        String capth = redisCache.getCacheObject(phone);
        if(!StringUtils.isEmpty(capth)){
            throw new GlobalExceptionHandler("你已发送验证码,请稍后再试~");
        }
        String code = ValidateCodeUtils.generateValidateCode(6).toString();
        //todo 发送验证码之后存入redis  时间为1分钟有效
        redisCache.setCacheObject(phone,code);
        //发送验证码存入redis中，并设置60秒后自动消亡
        redisCache.expire(phone,60L, TimeUnit.SECONDS);
        SMSUtils.sendMessage(signNameKey,templateCode,phone,code);
        return Boolean.TRUE;
    }

    /**
     * 修改密码mapper
     * @param pwdDto
     * @return
     */
    @Override
    public Boolean updatePwd(SysUserChangePwdBo pwdDto, HttpSession session) {
        SysUserInfo info =  sysUserInfoMapper.selectById(pwdDto.getUserId());
        boolean checkpw = BCrypt.checkpw(pwdDto.getPassword(), info.getPassword());
        if (!checkpw){
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_ORIGINAL_PASSOWRD_ERROR);
        }
        if (!pwdDto.getNewPwdone().equals(pwdDto.getNewPwdtwo())) {
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_PASSWORD_VAILD_TWICE);
        }
        String code = (String) session.getAttribute(CommonConstants.CHECK_CODE_KEY);
        if (!code.equalsIgnoreCase(pwdDto.getCode())){
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_CODE_ERROR);
        }
        //新加密的密码
        pwdDto.setNewPwdtwo(BCrypt.hashpw(pwdDto.getNewPwdtwo(), BCrypt.gensalt()));
        Boolean result = sysUserInfoMapper.updatePwd(pwdDto);
        return result;
    }

    @Override
    public SysUserInfoVo smslogin(SysUserSMSInfoBo cpUserSMSInfo) {
        String phone = cpUserSMSInfo.getPhone();
        SysUserInfoVo vo = sysUserInfoMapper.selectByPhone(phone);
        //手机号不存在
        if (ObjectUtils.isEmpty(vo)){
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_PHONE_NULL);
        }
        String captcha = redisCache.getCacheObject(phone);
        //验证码不存在
        if (!cpUserSMSInfo.getCode().equals(captcha)) {
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_CODE_ERROR);
        }
        //账号已被禁用
        if (vo.getStatus().equals(ResultCodeMsg.ACCOUNT_DISABLE.getCode() + "")){
            throw new GlobalExceptionHandler(ResultCodeMsg.ACCOUNT_DISABLE);
        }
        return vo;
    }

    @Override
    public Boolean userSpace(SysUserSpaceBo userSpaceBo) {
        QueryWrapper<SysUserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userSpaceBo.getUserId());
        SysUserInfo sysUserInfo = sysUserInfoMapper.selectOne(queryWrapper);

        Long useSpace = sysUserInfo.getUseSpace() + userSpaceBo.getFileTotal();
        Long totalSpace = sysUserInfo.getTotalSpace();
        if (useSpace <= totalSpace){
            return Boolean.TRUE;
        }

        return Boolean.FALSE;
    }

    /**
     * 判断是否为手机号登陆,false则学号登陆,true则手机号登陆
     * @param phone
     * @return
     */
    private static final String PATTERN_MODEL = "^1[3456789]\\d{9}$";

    public static Boolean isPhone(String phone){
        //学号true 手机号false
        Pattern phonePattern = Pattern.compile(PATTERN_MODEL);
        // 使用正则表达式进行匹配
        Matcher matcher = phonePattern.matcher(phone);
        // 返回匹配结果
        if (matcher.matches()) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadPhoto(MultipartFile file, String userId) {
        String photoName = file.getOriginalFilename();
        String contentType = file.getContentType();
        //String prefix = photoName.substring(0, photoName.lastIndexOf("."));
        String suffix = photoName.substring(photoName.lastIndexOf("."));
        String photoKey = UUID.randomUUID(false)  +  suffix;
        if (file.getSize() > 5 * 1024 * 1024){
            throw new GlobalExceptionHandler("你的头像大小大于5M,请重新选择头像上传");
        }
        if (!(suffix.equals(".jpg") || suffix.equals(".png") || suffix.equals(".jpeg"))){
            throw new GlobalExceptionHandler("你上传的图片格式不支持，请重新上传");
        }
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(contentType);
        try {
            InputStream inputStream = file.getInputStream();
            PutObjectRequest putObjectRequest = new PutObjectRequest("imgs", photoKey, inputStream, objectMetadata);
            amazonS3.putObject(putObjectRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = "http://192.168.18.10:9000/imgs/" + photoKey;
        SysUserInfo user = sysUserInfoMapper.selectById(userId);
        user.setAvatar(url);
        sysUserInfoMapper.updateById(user);

        return url;
    }
}
